﻿using System;
using System.Drawing;
using System.Linq;
using RaytracerLib;
using RaytracerLib.Layers;
using RaytracerLib.MathLib;
using RaytracerLib.RenderableObjects;
using RaytracerLib.Materials;
using RaytracerLib.Lights;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;
using RaytracerLib.Cameras;
using RaytracerLib.Samplers;

namespace Raytracer.Generator
{
    public static class Scenes
    {
        public static Scene Procedural_Layer(bool a_rotate = true, double a_plane_scale = 0.5, double a_sphere_scale = 6)
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            PlaneObject plane = new PlaneObject(new Vector3(0, 1, 0), new Vector3(0, 0, -1))
            {
                Name = "plane",
                Pos = new Vector3(0, -2, 0),
                DefaultMaterial = TestMaterials.CheckBoard("CheckBoard 1", ColorFloat.White,
                    new ColorFloat(0.5, 0, 0), a_sphere_scale, a_sphere_scale),
            };

            plane.RotateAroundUp(20);

            scene.RenderableObjects.Add(plane);

            SphereObject sphere = new SphereObject(Vector3.YAXIS, -Vector3.XAXIS)
            {
                Radius = 2,
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("CheckBoard 2", ColorFloat.White,
                    new ColorFloat(0.5, 0, 0), a_plane_scale, a_plane_scale),
                Name = "sphere"
            };

            if (a_rotate)
            {
                sphere.RotateAroundRight(45);
                sphere.RotateAroundForward(45);
            }
            else
            {
                sphere.Right = Vector3.XAXIS;
                sphere.Up = Vector3.YAXIS;
                sphere.Forward = Vector3.ZAXIS;
            }

            scene.RenderableObjects.Add(sphere);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-6, 1.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light1"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 1.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, 41.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 1, 1),
                Color = new ColorFloat(1),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 2.5, -6),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(sphere.Pos);

            return scene;
        }

        public static Scene Sphere_Refraction1(double a_checkboard_scale = 0.1, bool a_alter_check_colors = false)
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);
            if (a_alter_check_colors)
            {
                c1 = new ColorFloat(1, 1, 0);
                c2 = new ColorFloat(0, 1, 1);
            }

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = TestMaterials.CheckBoard("checkboard", c1, c2, a_checkboard_scale, a_checkboard_scale),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            SphereObject sphere = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Radius = 1,
                Pos = new Vector3(0, 0, -3),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "sphere"
            };

            scene.RenderableObjects.Add(sphere);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 4, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 0, -10),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, -4, -5),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Disc()
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = TestMaterials.CheckBoard("checkboard", c1, c2, 0.1, 0.1),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            DiscObject disc = new DiscObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Radius = 0.8,
                Pos = new Vector3(0, 0, -3),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue), 
                Name = "disc"
            };

            scene.RenderableObjects.Add(disc);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 4, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 0, -10),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, -4, -5),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Cone()
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = TestMaterials.CheckBoard("checkboard", c1, c2, 0.1, 0.1),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            ConeObject cone = new ConeObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Radius = 1, 
                Height = 1, 
                Pos = new Vector3(0, 0, -2),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue),
                BaseMaterial = TestMaterials.Solid("red", ColorFloat.SRGB_Red),
                Name = "cone"
            };

            scene.RenderableObjects.Add(cone);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 4, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 0, -10),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, -4, -5),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Cylinder()
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = TestMaterials.CheckBoard("checkboard", c1, c2, 0.1, 0.1),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            CylinderObject cylinder = new CylinderObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Radius = 1,
                Height = 1,
                Pos = new Vector3(0, 0, -2),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue),
                TopMaterial = TestMaterials.Solid("red", ColorFloat.SRGB_Red),
                BottomMaterial = TestMaterials.Solid("green", ColorFloat.SRGB_Green),
                Name = "cylinder"
            };

            scene.RenderableObjects.Add(cylinder);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 4, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 0, -10),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, -4, -5),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Superquadric()
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);

            var checkboard = TestMaterials.CheckBoard("checkboard", c1, c2, 0.1, 0.1);
            checkboard.ReflectionTransmittance = null;
            checkboard.SpecularHighlight = null;
            checkboard.SpecularHighlightExponent = null;

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = checkboard,
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = checkboard,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            SuperquadricObject sq = new SuperquadricObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Exponents = new Vector3(1, 1, 1), 
                Pos = new Vector3(0, 0, -2),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue),
                Name = "sq"
            };

            scene.RenderableObjects.Add(sq);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-6, 4, -13),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(5, 6, -14),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, -7, -15),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Superellipsoid()
        {
            Scene scene = new Scene();

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            double w = 10;

            ColorFloat c1 = ColorFloat.White;
            ColorFloat c2 = new ColorFloat(0.5, 0, 0);

            var checkboard = TestMaterials.CheckBoard("checkboard", c1, c2, 0.1, 0.1);
            checkboard.ReflectionTransmittance = null;
            checkboard.SpecularHighlight = null;
            checkboard.SpecularHighlightExponent = null;

            TriangleObject t1 = new TriangleObject(
                new Vector3(-w, -w, 0),
                new Vector3(-w, w, 0),
                new Vector3(w, w, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = checkboard,
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(w, w, 0),
                new Vector3(w, -w, 0),
                new Vector3(-w, -w, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = checkboard,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            SuperellipsoidObject se = new SuperellipsoidObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -2),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue),
                Name = "se"
            };

            scene.RenderableObjects.Add(se);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-6, 4, -13),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(5, 6, -14),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, -7, -15),
                Color = new ColorFloat(182 / 255.0),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -6),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Sphere_Refraction2()
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 1, 1)
            };

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            SphereObject sphere1 = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Radius = 2,
                Pos = new Vector3(7, 2.2, -5),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "sphere1"
            };

            sphere1.DefaultMaterial.RefractionTransmittance = LayersFactory.Solid(0.6);
            sphere1.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0.6);

            scene.RenderableObjects.Add(sphere1);

            SphereObject sphere2 = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Radius = 2,
                Pos = new Vector3(3, 2.6, -8),
                DefaultMaterial = sphere1.DefaultMaterial,
                Name = "sphere2"
            };

            scene.RenderableObjects.Add(sphere2);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(8, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(0.5 * (sphere1.Pos + sphere2.Pos));

            return scene;
        }

        public static Scene Cone_Refraction()
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 1, 1)
            };

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            ConeObject cone = new ConeObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Radius = 4,
                Height = 4,
                Pos = new Vector3(7, 5, -5),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                BaseMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "cone"
            };

            cone.DefaultMaterial.RefractionTransmittance = LayersFactory.Solid(0.6);
            cone.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0.6);

            scene.RenderableObjects.Add(cone);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(8, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(cone.Pos);

            return scene;
        }

        public static Scene PolynomialSurface(PolynomialSurfaceInfo a_info, bool a_refraction = false)
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 6, 6)
            };

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 6, 6)
            };

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 6, 6)
            };

            plane1.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0);
            plane2.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0);
            plane3.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0);

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            PolynomialSurface poly_surf = new PolynomialSurface(Vector3.XAXIS, Vector3.YAXIS)
            {
                Equation = a_info.Equation,
                Closed = a_info.Closed,
                Name = a_info.Name,
                Parameter1 = a_info.Parameter1,
                Parameter2 = a_info.Parameter2,
                Parameter3 = a_info.Parameter3,
                Pos = new Vector3(9, 5, -14),
                DefaultMaterial = a_refraction ? TestMaterials.Refractive("Glass", new ColorFloat(0.1)) : 
                    TestMaterials.Shiny("shiny", ColorFloat.SRGB_Blue, 1, 1, 0, 150)
            };

            scene.RenderableObjects.Add(poly_surf);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(18, 6, -20),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(22, 30, -20),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(8, 2, -20),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(12, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(poly_surf.Pos);

            return scene;
        }

        public static Scene PolynomialSurface_Refraction(PolynomialSurfaceInfo a_info)
        {
            return PolynomialSurface(a_info, true);
        }

        public static Scene Cylinder_Refraction()
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 1, 1)
            };

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            CylinderObject cylinder = new CylinderObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Radius = 4,
                Height = 4,
                Pos = new Vector3(7, 5, -5),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                TopMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                BottomMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "cylinder"
            };

            cylinder.DefaultMaterial.RefractionTransmittance = LayersFactory.Solid(0.6);
            cylinder.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0.6);

            scene.RenderableObjects.Add(cylinder);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(8, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(cylinder.Pos);

            return scene;
        }

        public static Scene Superquadric_Refraction()
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            plane1.DefaultMaterial.ReflectionTransmittance = null;
            plane1.DefaultMaterial.SpecularHighlight = null;
            plane1.DefaultMaterial.SpecularHighlightExponent = null;

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            plane2.DefaultMaterial.ReflectionTransmittance = null;
            plane2.DefaultMaterial.SpecularHighlight = null;
            plane2.DefaultMaterial.SpecularHighlightExponent = null;

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 1, 1)
            };

            plane3.DefaultMaterial.ReflectionTransmittance = null;
            plane3.DefaultMaterial.SpecularHighlight = null;
            plane3.DefaultMaterial.SpecularHighlightExponent = null;

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            SuperquadricObject sq = new SuperquadricObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Pos = new Vector3(7, 5, -5),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "sq",
                Scale = new Vector3(3, 3, 3)
            };

            sq.DefaultMaterial.RefractionTransmittance = LayersFactory.Solid(0.6);
            sq.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0.6);

            scene.RenderableObjects.Add(sq);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(8, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(sq.Pos);

            return scene;
        }

        public static Scene Superellipsoid_Refraction()
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            plane1.DefaultMaterial.ReflectionTransmittance = null;
            plane1.DefaultMaterial.SpecularHighlight = null;
            plane1.DefaultMaterial.SpecularHighlightExponent = null;

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            plane2.DefaultMaterial.ReflectionTransmittance = null;
            plane2.DefaultMaterial.SpecularHighlight = null;
            plane2.DefaultMaterial.SpecularHighlightExponent = null;

            PlaneObject plane3 = new PlaneObject(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Name = "plane3",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_green_yellow",
                    ColorFloat.SRGB_Yellow, ColorFloat.SRGB_Green, 1, 1)
            };

            plane3.DefaultMaterial.ReflectionTransmittance = null;
            plane3.DefaultMaterial.SpecularHighlight = null;
            plane3.DefaultMaterial.SpecularHighlightExponent = null;

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);
            scene.RenderableObjects.Add(plane3);

            SuperellipsoidObject se = new SuperellipsoidObject(Vector3.XAXIS, -Vector3.YAXIS)
            {
                Pos = new Vector3(7, 5, -5),
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1)),
                Name = "se",
                Scale = new Vector3(3, 3, 3)
            };

            se.DefaultMaterial.RefractionTransmittance = LayersFactory.Solid(0.6);
            se.DefaultMaterial.ReflectionTransmittance = LayersFactory.Solid(0.6);

            scene.RenderableObjects.Add(se);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(0.7),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.6),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.6),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(8, 6, -20),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(se.Pos);

            return scene;
        }

        public static Scene Planes_Refraction(double a_box_height,
            double a_box_refraction_index = RefractiveIndices.OpticGlass1, 
            string a_material_name = "Glass")
        {
            Scene scene = new Scene();

            PlaneObject plane1 = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane1",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_red",
                    ColorFloat.SRGB_Red, ColorFloat.White, 1, 1)
            };

            PlaneObject plane2 = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane2",
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.CheckBoard("checkboard_blue",
                    ColorFloat.White, ColorFloat.SRGB_Blue, 1, 1)
            };

            scene.RenderableObjects.Add(plane1);
            scene.RenderableObjects.Add(plane2);

            Material m = TestMaterials.Refractive(a_material_name, ColorFloat.White);
            m.ReflectionTransmittance = LayersFactory.Solid(0.6);
            m.RefractionTransmittance = LayersFactory.Solid(0.6);
            m.RefractionIndice = a_box_refraction_index;
            CreateBox(scene, new Vector3(-1, 3, 0.001), new Vector3(1, 3 - a_box_height, -30), m);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(10, 6, -5),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 5, -12),
                Color = new ColorFloat(0.61),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(9, 7, -15),
                Color = new ColorFloat(0.61),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 5, -35),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(new Vector3(0, 1, 16));

            return scene;
        }

        private static void CreateBox(Scene a_scene, Vector3 a_v1, Vector3 a_v2,
            Material a_material)
        {
            Vector3 v1 = new Vector3(
                Math.Min(a_v1.X, a_v2.X),
                Math.Max(a_v1.Y, a_v2.Y),
                Math.Max(a_v1.Z, a_v2.Z));

            Vector3 v2 = new Vector3(
                Math.Max(a_v1.X, a_v2.X),
                Math.Max(a_v1.Y, a_v2.Y),
                Math.Max(a_v1.Z, a_v2.Z));

            Vector3 v3 = new Vector3(
                Math.Max(a_v1.X, a_v2.X),
                Math.Max(a_v1.Y, a_v2.Y),
                Math.Min(a_v1.Z, a_v2.Z));

            Vector3 v4 = new Vector3(
                Math.Min(a_v1.X, a_v2.X),
                Math.Max(a_v1.Y, a_v2.Y),
                Math.Min(a_v1.Z, a_v2.Z));

            Vector3 v5 = new Vector3(
                Math.Min(a_v1.X, a_v2.X),
                Math.Min(a_v1.Y, a_v2.Y),
                Math.Max(a_v1.Z, a_v2.Z));

            Vector3 v6 = new Vector3(
                Math.Max(a_v1.X, a_v2.X),
                Math.Min(a_v1.Y, a_v2.Y),
                Math.Max(a_v1.Z, a_v2.Z));

            Vector3 v7 = new Vector3(
                Math.Min(a_v1.X, a_v2.X),
                Math.Min(a_v1.Y, a_v2.Y),
                Math.Min(a_v1.Z, a_v2.Z));

            Vector3 v8 = new Vector3(
                Math.Max(a_v1.X, a_v2.X),
                Math.Min(a_v1.Y, a_v2.Y),
                Math.Min(a_v1.Z, a_v2.Z));

            CreateRect(a_scene, v1, v2, v3, v4, a_material, true);

            if (!a_v1.Y.IsAlmostRelativeEquals(a_v2.Y))
            {
                CreateRect(a_scene, v1, v5, v6, v2, a_material, true);
                CreateRect(a_scene, v3, v2, v6, v8, a_material, true);
                CreateRect(a_scene, v4, v7, v5, v1, a_material, true);
                CreateRect(a_scene, v7, v8, v6, v5, a_material, true);
                CreateRect(a_scene, v7, v4, v3, v8, a_material, true);
            }
        }

        private static void CreateRect(Scene a_scene, Vector3 a_v1, Vector3 a_v2,
            Vector3 a_v3, Vector3 a_v4, Material a_material, bool a_closed)
        {
            CreateTriangle(a_scene, a_v1, a_v2, a_v3, a_material, a_closed);
            CreateTriangle(a_scene, a_v1, a_v3, a_v4, a_material, a_closed);
        }

        private static void CreateTriangle(Scene a_scene, Vector3 a_v1, Vector3 a_v2,
            Vector3 a_v3, Material a_material, bool a_closed)
        {
            var tr = new TriangleObject(a_v1, a_v2, a_v3)
            {
                Name = "tr",
                DefaultMaterial = a_material, 
                Closed = a_closed
            };

            a_scene.RenderableObjects.Add(tr);
        }

        public static Scene Sphere_Inside()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            SphereObject sphere = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Radius = 2,
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.EarthSimple("earth"),
                Name = "sphere"
            };

            scene.RenderableObjects.Add(sphere);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, 0, -1.99),
                Color = new ColorFloat(1),
                Name = "light"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -1.99),
                Name = "camera",
                MinimalPlaneDistant = 3.3
            };

            scene.ActiveCamera.SetLookAt(sphere.Pos);

            return scene;
        }

        public static Scene Triangles_Bump()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            TriangleObject t1 = new TriangleObject(
                new Vector3(-1.5, -1.5, 0),
                new Vector3(-1.5, 1.5, 0),
                new Vector3(1.5, 1.5, 0))
            {
                T1 = t11,
                T2 = t12,
                T3 = t22,
                Name = "t1",
                DefaultMaterial = TestMaterials.BumpCircle("BumpCircle"),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(1.5, 1.5, 0),
                new Vector3(1.5, -1.5, 0),
                new Vector3(-1.5, -1.5, 0))
            {
                T1 = t22,
                T2 = t21,
                T3 = t11,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            PlaneObject plane = new PlaneObject(-Vector3.ZAXIS, -1, Vector3.XAXIS)
            {
                Name = "plane",
                DefaultMaterial = TestMaterials.Wood("wood")
            };

            Layer.GetAllArrays(t1.DefaultMaterial.Tangents as Layer).First().
                TangentsPixelDelta = 0.1;
            Layer.GetAllArrays(t1.DefaultMaterial.Tangents as Layer).First().
                TangentsScale = 40;

            scene.RenderableObjects.Add(plane);

            OmniLight light = new OmniLight()
            {
                Pos = new Vector3(0, 0, -0.2),
                Color = new ColorFloat(1),
                Name = "light1"
            };

            scene.Lights.Add(light);

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -4),
                Name = "camera"
            };

            (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

            return scene;
        }

        public static Scene Sphere_Bump(bool a_move)
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            SphereObject sphere = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Name = "sphere",
                Pos = new Vector3(0, 0, 0),
                Radius = 1,
                DefaultMaterial = TestMaterials.BumpCircle("BumpCircle"),
            };

            Layer.SetScale(sphere.DefaultMaterial.Diffuse as Layer,
                new Vector2(0.15, 0.15));
            Layer.SetScale(sphere.DefaultMaterial.Tangents as Layer,
                new Vector2(0.15, 0.15));

            scene.RenderableObjects.Add(sphere);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, 0.6, -1.1),
                Color = new ColorFloat(1),
                Name = "light"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0.5, -5),
                FOV = 20,
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(new Vector3(0.2, 0.5, 0));

            if (a_move)
            {
                var delta = new Vector3(2, -3, 5);
                scene.ActiveCamera.Pos += delta;
                sphere.Pos += delta;
                scene.Lights[0].Pos += delta;
            }

            return scene;
        }

        public static Scene Sphere_Earth()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            SphereObject sphere = new SphereObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                Name = "sphere",
                DefaultMaterial = TestMaterials.Earth("Earth"),
                Radius = 1.6,
                Pos = new Vector3(0, 0, 0)
            };

            scene.RenderableObjects.Add(sphere);

            PlaneObject plane = new PlaneObject(new Vector3(0, 1, 0), new Vector3(1, 0, -2))
            {
                Name = "plane",
                Pos = sphere.Pos - Vector3.YAXIS * sphere.Radius * 1.2,
                DefaultMaterial = TestMaterials.Wood("Wood"),
            };

            scene.RenderableObjects.Add(plane);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-6, 1.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light1"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 1.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, 41.5, -20),
                Color = new ColorFloat(182 / 255.0),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(6, 1, 1),
                Color = new ColorFloat(1),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = sphere.Pos - Vector3.ZAXIS * 5,
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(sphere.Pos);

            return scene;
        }

        public static Scene Plane(Vector3 a_camera_pos, double a_scale,
            OverlayMethod a_overlay_method, InterpolationMethod a_interpolation_method)
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            PlaneObject plane = new PlaneObject(Vector3.YAXIS, Vector3.XAXIS)
            {
                Name = "plane",
                Pos = Vector3.ZERO,
                DefaultMaterial = TestMaterials.Wood("Wood")
            };

            scene.RenderableObjects.Add(plane);

            Layer.SetScale(plane.DefaultMaterial.Diffuse as Layer,
                new Vector2(a_scale, a_scale * 1854 / 2560));

            foreach (var array in Layer.GetAllArrays(
                 plane.DefaultMaterial.Diffuse as Layer))
            {
                array.OverlayMethod = a_overlay_method;
                array.InterpolationMethod = a_interpolation_method;
            }

            scene.Lights.Add(new OmniLight()
            {
                Pos = a_camera_pos - Vector3.XAXIS * 10,
                Color = new ColorFloat(0.78),
                Name = "light1"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = a_camera_pos + Vector3.XAXIS * 10,
                Color = new ColorFloat(0.78),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = a_camera_pos - Vector3.ZAXIS * 10,
                Color = new ColorFloat(0.78),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = a_camera_pos + Vector3.ZAXIS * 10,
                Color = new ColorFloat(0.78),
                Name = "light4"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.ZAXIS)
            {
                Pos = a_camera_pos,
                Name = "camera"
            };

            return scene;
        }

        public static Scene Plane_Bump(bool a_center = false)
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            PlaneObject plane = new PlaneObject(-Vector3.ZAXIS, Vector3.XAXIS)
            {
                Name = "plane",
                Pos = Vector3.ZERO,
                DefaultMaterial = TestMaterials.BumpCircle("BumpCircle")
            };

            Layer.GetAllArrays(plane.DefaultMaterial.Tangents as Layer).First().TangentsScale = 10;
            Layer.SetScale(plane.DefaultMaterial.Diffuse as Layer, new Vector2(1.9, 1.9));
            Layer.SetScale(plane.DefaultMaterial.Tangents as Layer, new Vector2(1.9, 1.9));

            scene.RenderableObjects.Add(plane);

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(-2.8, 1, -3),
                MinimalPlaneDistant = 0.1,
                Name = "camera"
            };

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-2.82, 0.94, -0.2),
                Color = new ColorFloat(1),
                Name = "light"
            });

            if (a_center)
            {
                scene.ActiveCamera.Pos = new Vector3(0, 0, scene.ActiveCamera.Pos.Z);
                scene.Lights[0].Pos = new Vector3(0, 0, scene.Lights[0].Pos.Z);
            }

            (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

            return scene;
        }

        public static Scene Light_Adjustment()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            SphereObject sphere1 = new SphereObject(Vector3.ZAXIS, Vector3.YAXIS)
            {
                Name = "sphere1",
                Pos = new Vector3(0, 0, 0),
                Radius = 1,
                DefaultMaterial = TestMaterials.Shiny("Shiny", new ColorFloat(0.2, 0.2, 0.2))
            };

            scene.RenderableObjects.Add(sphere1);

            OmniLight light1 = new OmniLight()
            {
                Pos = new Vector3(5, 5, -10),
                Color = new ColorFloat(1, 2, 3),
                Name = "light1"
            };

            OmniLight light2 = new OmniLight()
            {
                Pos = new Vector3(-5, 5, -10),
                Color = new ColorFloat(3, 2, 1),
                Name = "light2"
            };

            scene.Lights.Add(light1);
            scene.Lights.Add(light2);

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -10),
                Name = "camera"
            };

            return scene;
        }

        public static Scene Spheres_Two_above_plane()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            PlaneObject plane = new PlaneObject(new Vector3(0, 1, 0),
                new Vector3(1, 0, -1))
            {
                Name = "plane",
                Pos = new Vector3(0, -1.5, 0),
                DefaultMaterial = TestMaterials.Wood("Wood")
            };

            scene.RenderableObjects.Add(plane);

            SphereObject sphere1 = new SphereObject(-Vector3.ZAXIS, Vector3.YAXIS)
            {
                Name = "sphere1",
                Pos = new Vector3(1.5, 0, 0),
                Radius = 1,
                DefaultMaterial = TestMaterials.Shiny("ShinyGreen", ColorFloat.SRGB_Green)
            };

            scene.RenderableObjects.Add(sphere1);

            SphereObject sphere2 = new SphereObject(-Vector3.ZAXIS, Vector3.YAXIS)
            {
                Name = "sphere2",
                Pos = new Vector3(-1, 0, 0),
                Radius = 0.5,
                DefaultMaterial = TestMaterials.Shiny("ShinyRed", ColorFloat.SRGB_Red)
            };

            scene.RenderableObjects.Add(sphere2);

            OmniLight light1 = new OmniLight()
            {
                Pos = new Vector3(-2, 2.5, 0),
                Color = new ColorFloat(0.77, 0.31, 0.31),
                Name = "light1"
            };

            OmniLight light2 = new OmniLight()
            {
                Pos = new Vector3(1.5, 2.5, 1.5),
                Color = new ColorFloat(0.31, 0.31, 0.77),
                Name = "light2"
            };

            OmniLight light3 = new OmniLight()
            {
                Pos = new Vector3(1.5, 2.5, -1.5),
                Color = new ColorFloat(0.31, 0.77, 0.31),
                Name = "light3"
            };

            OmniLight light4 = new OmniLight()
            {
                Pos = new Vector3(0, 3.5, 0),
                Color = new ColorFloat(0.52, 0.52, 0.66),
                Name = "light4"
            };

            scene.Lights.Add(light1);
            scene.Lights.Add(light2);
            scene.Lights.Add(light3);
            scene.Lights.Add(light4);

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 2, -10),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(Vector3.ZERO);

            return scene;
        }

        public static Scene Triangles_Earth()
        {
            Scene scene = new Scene();

            scene.RenderOptions.AmbientColor = new ColorFloat(27 / 255.0);

            var t11 = new Vector2(0, 0);
            var t12 = new Vector2(0, 1);
            var t21 = new Vector2(1, 0);
            var t22 = new Vector2(1, 1);

            TriangleObject t1 = new TriangleObject(
                new Vector3(-3, -1.5, 0),
                new Vector3(-3, 1.5, 0),
                new Vector3(3, 1.5, 0))
            {
                T1 = t12,
                T2 = t11,
                T3 = t21,
                Name = "t1",
                DefaultMaterial = TestMaterials.Earth("Earth"),
                OneSide = true
            };

            TriangleObject t2 = new TriangleObject(
                new Vector3(3, 1.5, 0),
                new Vector3(3, -1.5, 0),
                new Vector3(-3, -1.5, 0))
            {
                T1 = t21,
                T2 = t22,
                T3 = t12,
                Name = "t2",
                DefaultMaterial = t1.DefaultMaterial,
                OneSide = false
            };

            scene.RenderableObjects.Add(t1);
            scene.RenderableObjects.Add(t2);

            PlaneObject plane = new PlaneObject(-Vector3.ZAXIS, -1, Vector3.XAXIS)
            {
                Name = "plane",
                DefaultMaterial = TestMaterials.Wood("wood")
            };

            scene.RenderableObjects.Add(plane);

            OmniLight light1 = new OmniLight()
            {
                Pos = new Vector3(-6, -6, -10),
                Color = new ColorFloat(0.78),
                Name = "light1"
            };

            OmniLight light2 = new OmniLight()
            {
                Pos = new Vector3(-6, 6, -10),
                Color = new ColorFloat(0.78),
                Name = "light2"
            };

            OmniLight light3 = new OmniLight()
            {
                Pos = new Vector3(6, -6, -10),
                Color = new ColorFloat(0.78),
                Name = "light3"
            };

            OmniLight light4 = new OmniLight()
            {
                Pos = new Vector3(6, 6, -10),
                Color = new ColorFloat(0.78),
                Name = "light4"
            };

            scene.Lights.Add(light1);
            scene.Lights.Add(light2);
            scene.Lights.Add(light3);
            scene.Lights.Add(light4);

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, -4, -7),
                Name = "camera"
            };

            scene.ActiveCamera.SetLookAt(new Vector3(0, 0, 0));

            return scene;
        }

        public static Scene Torus_Refraction(double a_refra = RefractiveIndices.Air)
        {
            Scene scene = Scenes.Sphere_Refraction1();
            scene.RenderableObjects["sphere"].Remove();

            TorusObject torus = new TorusObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                BigRadius = 0.25,
                SmallRadius = 0.5,
                Pos = new Vector3(0, 0, -2),
                Name = "torus",
                DefaultMaterial = TestMaterials.Refractive("Glass", new ColorFloat(0.1), false,
                    a_refra, 0.9, 0.9),
            };
            scene.RenderableObjects.Add(torus);
            scene.Materials["checkboard"].ReflectionTransmittance = null;
            scene.Materials["checkboard"].SpecularHighlight = null;
            scene.Materials["checkboard"].SpecularHighlightExponent = null;
            scene.Materials["Glass"].Diffuse = null;
            scene.Materials["Glass"].SpecularHighlight = null;
            scene.Materials["Glass"].SpecularHighlightExponent = null;
            scene.Lights["light3"].Remove();
            scene.Lights["light4"].Remove();
            scene.Lights["light2"].Color = ColorFloat.White;
            scene.Lights["light2"].Pos = scene.ActiveCamera.Pos;
            scene.Lights["light2"].Name = "light";
            return scene;
        }

        public static Scene Torus()
        {
            Scene scene = new Scene();

            TorusObject torus = new TorusObject(Vector3.XAXIS, Vector3.YAXIS)
            {
                BigRadius = 4,
                SmallRadius = 1, 
                Pos = new Vector3(0, 0, 0),
                DefaultMaterial = TestMaterials.Solid("blue", ColorFloat.SRGB_Blue), 
                Name = "torus"
            };

            scene.RenderableObjects.Add(torus);

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, 3, -14),
                Color = new ColorFloat(0.5),
                Name = "light1"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(3, -3, -14),
                Color = new ColorFloat(0.5),
                Name = "light2"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-3, 3, -14),
                Color = new ColorFloat(0.5),
                Name = "light3"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(-3, -3, -14),
                Color = new ColorFloat(0.5),
                Name = "light4"
            });

            scene.Lights.Add(new OmniLight()
            {
                Pos = new Vector3(0, 0, -14),
                Color = new ColorFloat(0.5),
                Name = "light"
            });

            scene.ActiveCamera = new PerspectiveCamera(Vector3.XAXIS, Vector3.YAXIS)
            {
                Pos = new Vector3(0, 0, -14),
                Name = "camera"
            };

            return scene;
        }
    }
}